home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / security / CodeSource.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  14.4 KB  |  483 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)CodeSource.java    1.26 98/09/15
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.security;
  16.  
  17.  
  18. import java.net.URL;
  19. import java.net.SocketPermission;
  20. import java.util.Hashtable;
  21. import java.io.ByteArrayInputStream;
  22. import java.io.IOException;
  23. import java.security.cert.*;
  24.  
  25. /**
  26.  *
  27.  * <p>This class extends the concept of a codebase to
  28.  * encapsulate not only the location (URL) but also the certificate(s)
  29.  * that were used to verify signed code originating from that
  30.  * location.
  31.  *
  32.  * @version     1.26, 09/15/98
  33.  * @author Li Gong
  34.  * @author Roland Schemers
  35.  */
  36.  
  37. public class CodeSource implements java.io.Serializable {
  38.  
  39.     /**
  40.      * The code location.
  41.      *
  42.      * @serial
  43.      */
  44.     private URL location;
  45.  
  46.     // certificates
  47.     private transient java.security.cert.Certificate certs[];
  48.  
  49.     // cached SocketPermission used for matchLocation
  50.     private transient SocketPermission sp;
  51.  
  52.     /**
  53.      * Constructs a CodeSource and associates it with the specified 
  54.      * location and set of certificates.
  55.      * 
  56.      * @param url the location (URL).
  57.      * 
  58.      * @param certs the certificate(s).
  59.      */
  60.     public CodeSource(URL url, java.security.cert.Certificate certs[]) {
  61.     this.location = url;
  62.     if (certs != null) 
  63.         this.certs = (java.security.cert.Certificate[]) certs.clone();
  64.     }
  65.  
  66.     /**
  67.      * Returns the hash code value for this object.
  68.      *
  69.      * @return a hash code value for this object.
  70.      */
  71.  
  72.     public int hashCode() {
  73.     if (location != null)
  74.         return location.hashCode();
  75.     else 
  76.         return 0;
  77.     }
  78.  
  79.     /**
  80.      * Tests for equality between the specified object and this
  81.      * object. Two CodeSource objects are considered equal if their 
  82.      * locations are of identical value and if the two sets of 
  83.      * certificates are of identical values. It is not required that
  84.      * the certificates be in the same order.
  85.      * 
  86.      * @param obj the object to test for equality with this object.
  87.      * 
  88.      * @return true if the objects are considered equal, false otherwise.
  89.      */
  90.     public boolean equals(Object obj) {
  91.     if (obj == this) 
  92.         return true;
  93.  
  94.     // objects types must be equal
  95.     if (!(obj instanceof CodeSource))
  96.         return false;
  97.  
  98.     CodeSource cs = (CodeSource) obj;
  99.  
  100.     // URLs must match
  101.     if (location == null) {
  102.         // if location is null, then cs.location must be null as well
  103.         if (cs.location != null) return false;
  104.     } else {
  105.         // if location is not null, then it must equal cs.location
  106.         if (!location.equals(cs.location)) return false;
  107.     }
  108.  
  109.     // certs must match
  110.     if (certs == null) {
  111.         // if certs is null, then cs.certs must be null as well
  112.         if (cs.certs != null) return false;
  113.     } else {
  114.         // if certs is not null, then it must equal cs.certs
  115.         // equality means that both arrays of certs are the same set
  116.         // step 1 -- every cert in certs[] must match one in cs.certs[]
  117.         if (cs.certs == null) 
  118.         return false;
  119.  
  120.         boolean match;
  121.         for (int i = 0; i < certs.length; i++) {
  122.         match = false;
  123.         for (int j = 0; j < cs.certs.length; j++) {
  124.             if (certs[i].equals(cs.certs[j])) {
  125.             match = true;
  126.             break;
  127.             }
  128.         }
  129.         if (!match) return false;
  130.         }
  131.         // step 2 -- every key in cs.certs[] must match one in certs[]
  132.         for (int i = 0; i < cs.certs.length; i++) {
  133.         match = false;
  134.         for (int j = 0; j < certs.length; j++) {
  135.             if (cs.certs[i].equals(certs[j])) {
  136.             match = true;
  137.             break;
  138.             }
  139.         }
  140.         if (!match) return false;
  141.         }
  142.     }
  143.        
  144.     // they must be equal if we got here...
  145.     return true;
  146.     }
  147.  
  148.     /**
  149.      * Returns the location associated with this CodeSource.
  150.      * 
  151.      * @return the location (URL).
  152.      */
  153.     public final URL getLocation() {
  154.     /* since URL is practically immutable, returning itself is not
  155.            a security problem */
  156.     return this.location;
  157.     }
  158.  
  159.     /**
  160.      * Returns the certificates associated with this CodeSource.
  161.      * 
  162.      * @return the certificates
  163.      */
  164.     public final java.security.cert.Certificate[] getCertificates() {
  165.     /* return a clone copy, to avoid malicious modification to the
  166.        original object */
  167.     if (this.certs != null) {
  168.         return (java.security.cert.Certificate[])this.certs.clone();
  169.     } else {
  170.         return null;
  171.     }
  172.     }
  173.  
  174.     /**
  175.      * Returns true if this CodeSource object "implies" the specified CodeSource.
  176.      * <P>
  177.      * More specifically, this method makes the following checks, in order. 
  178.      * If any fail, it returns false. If they all succeed, it returns true.<p>
  179.      * <ol>
  180.      * <li> <i>codesource</i> must not be null.
  181.      * <li> If this object's certificates are not null, then all
  182.      * of this object's certificates must be present in <i>codesource</i>'s 
  183.      * certificates.
  184.      * <li> If this object's location (getLocation()) is not null, then the 
  185.      * following checks are made against this object's location and 
  186.      * <i>codesource</i>'s:<p>
  187.      *   <ol>
  188.      *     <li>  <i>codesource</i>'s location must not be null.
  189.      *
  190.      *     <li>  If this object's location 
  191.      *           equals <i>codesource</i>'s location, then return true.
  192.      *
  193.      *     <li>  This object's protocol (getLocation().getProtocol()) must be
  194.      *           equal to <i>codesource</i>'s protocol.
  195.      *
  196.      *     <li>  If this object's host (getLocation().getHost()) is not null,  
  197.      *           then the SocketPermission
  198.      *           constructed with this object's host must imply the
  199.      *           SocketPermission constructed with <i>codesource</i>'s host.
  200.      *
  201.      *     <li>  If this object's port (getLocation().getPort()) is not 
  202.      *           equal to -1 (that is, if a port is specified), it must equal 
  203.      *           <i>codesource</i>'s port.
  204.      *
  205.      *     <li>  If this object's file (getLocation().getFile()) doesn't equal
  206.      *           <i>codesource</i>'s file, then the following checks are made:
  207.      *           If this object's file ends with "/-",
  208.      *           then <i>codesource</i>'s file must start with this object's
  209.      *           file (exclusive the trailing "-").
  210.      *           If this object's file ends with a "/*",
  211.      *           then <i>codesource</i>'s file must start with this object's
  212.      *           file and must not have any further "/" separators.
  213.      *           If this object's file doesn't end with a "/", 
  214.      *           then <i>codesource</i>'s file must match this object's 
  215.      *           file with a '/' appended.
  216.      *
  217.      *     <li>  If this object's reference (getLocation().getRef()) is 
  218.      *           not null, it must equal <i>codesource</i>'s reference.
  219.      *
  220.      *   </ol>
  221.      * </ol>
  222.      * <p>
  223.      * For example, the codesource objects with the following locations
  224.      * and null certificates all imply
  225.      * the codesource with the location "http://java.sun.com/classes/foo.jar"
  226.      * and null certificates:
  227.      * <pre>
  228.      *     http:
  229.      *     http://*.sun.com/classes/*
  230.      *     http://java.sun.com/classes/-
  231.      *     http://java.sun.com/classes/foo.jar
  232.      * </pre>
  233.      *
  234.      * @param codesource CodeSource to compare against.
  235.      *
  236.      * @return true if the specified codesource is implied by this codesource,
  237.      * false if not.  
  238.      */
  239.  
  240.     public boolean implies(CodeSource codesource)
  241.     {
  242.     if (codesource == null)
  243.         return false;
  244.  
  245.     return matchCerts(codesource) && matchLocation(codesource);
  246.     }
  247.  
  248.    
  249.     /**
  250.      * Returns true if all the certs in this
  251.      * CodeSource are also in <i>that</i>.
  252.      * 
  253.      * @param that the CodeSource to check against.
  254.      */
  255.     private boolean matchCerts(CodeSource that)
  256.     {
  257.     // match any key
  258.     if (this.certs == null) 
  259.         return true;
  260.  
  261.     // if certs are null, and this.certs is not null, return false
  262.     if (that.certs == null)
  263.         return false;
  264.  
  265.     boolean match;
  266.     for (int i=0; i < this.certs.length; i++) {
  267.         match = false;
  268.         for (int j=0; j < that.certs.length; j++) {
  269.         if (this.certs[i].equals(that.certs[j])) {
  270.             match = true;
  271.             break;
  272.         }
  273.         }
  274.         if (!match) return false;
  275.     }
  276.     return true;
  277.     }
  278.  
  279.     /**
  280.      * Returns true if two CodeSource's have the "same" location.
  281.      * 
  282.      * @param that CodeSource to compare against
  283.      */
  284.     private boolean matchLocation(CodeSource that)
  285.     {
  286.         if (location == null) {
  287.         return true;
  288.         }
  289.  
  290.         if ((that == null) || (that.location == null))
  291.         return false;
  292.  
  293.         if (location.equals(that.location))
  294.         return true;
  295.  
  296.         if (!location.getProtocol().equals(that.location.getProtocol()))
  297.         return false;
  298.  
  299.         if ((location.getHost() != null)) {
  300.         if ((location.getHost().equals("") || 
  301.             location.getHost().equals("localhost")) &&
  302.             (that.location.getHost().equals("") || 
  303.              that.location.getHost().equals("localhost"))) {
  304.             // ok
  305.         } else if (!location.getHost().equals(
  306.                          that.location.getHost())) {
  307.             if (this.sp == null) {
  308.             this.sp = 
  309.                 new SocketPermission(location.getHost(),"resolve");
  310.             }
  311.             if (that.sp == null) {
  312.             if (that.location.getHost() == null ||
  313.                 that.location.getHost().equals(""))
  314.                 return false;
  315.             that.sp = 
  316.                new SocketPermission(that.location.getHost(),"resolve");
  317.             }
  318.  
  319.             boolean ok = this.sp.implies(that.sp);
  320.             if (!ok)
  321.             return false;
  322.         }
  323.         }
  324.  
  325.         if (location.getPort() != -1) {
  326.         if (location.getPort() != that.location.getPort())
  327.             return false;
  328.         }
  329.  
  330.         if (location.getFile().endsWith("/-")) {
  331.         // Matches the directory and (recursively) all files
  332.         // and subdirectories contained in that directory.
  333.         // For example, "/a/b/-" implies anything that starts with
  334.         // "/a/b/"
  335.         String thisPath = location.getFile().substring(0,
  336.                                                 location.getFile().length()-1);
  337.         if (!that.location.getFile().startsWith(thisPath))
  338.             return false;
  339.         } else if (location.getFile().endsWith("/*")) {
  340.         // Matches the directory and all the files contained in that
  341.         // directory.
  342.         // For example, "/a/b/*" implies anything that starts with
  343.         // "/a/b/" but has no further slashes
  344.         int last = that.location.getFile().lastIndexOf('/');
  345.         if (last == -1) 
  346.             return false;
  347.         String thisPath = location.getFile().substring(0,
  348.                                                 location.getFile().length()-1);
  349.         String thatPath = that.location.getFile().substring(0, last+1);
  350.         if (!thatPath.equals(thisPath))
  351.             return false;
  352.         } else {
  353.         // Exact matches only.
  354.         // For example, "/a/b" and "/a/b/" both imply "/a/b/" 
  355.         if ((!that.location.getFile().equals(location.getFile()))
  356.         && (!that.location.getFile().equals(location.getFile()+"/"))) {
  357.             return false;
  358.         }
  359.         }
  360.  
  361.         if (location.getRef() == null)
  362.         return true;
  363.         else 
  364.         return location.getRef().equals(that.location.getRef());
  365.     }
  366.  
  367.     /**
  368.      * Returns a string describing this CodeSource, telling its
  369.      * URL and certificates.
  370.      * 
  371.      * @return information about this CodeSource.
  372.      */
  373.     public String toString() {
  374.     StringBuffer sb = new StringBuffer();
  375.     sb.append("(");
  376.     sb.append(this.location);
  377.     if (this.certs != null && this.certs.length > 0) {
  378.         for (int i=0; i < this.certs.length; i++) {
  379.         sb.append( " "+this.certs[i]);
  380.         }
  381.     } else {
  382.         sb.append(" <no certificates>");
  383.     }
  384.     sb.append(")");
  385.     return sb.toString();
  386.     }
  387.  
  388.     /**
  389.      * Writes this object out to a stream (i.e., serializes it).
  390.      *
  391.      * @serialData An initial <code>URL</code> is followed by an
  392.      * <code>int</code> indicating the number of certificates to follow 
  393.      * (a value of "zero" denotes that there are no certificates associated
  394.      * with this object).
  395.      * Each certificate is written out starting with a <code>String</code>
  396.      * denoting the certificate type, followed by an
  397.      * <code>int</code> specifying the length of the certificate encoding,
  398.      * followed by the certificate encoding itself which is written out as an
  399.      * array of bytes.
  400.      */
  401.     private synchronized void writeObject(java.io.ObjectOutputStream oos)
  402.         throws IOException
  403.     {
  404.     oos.defaultWriteObject();
  405.  
  406.     if (certs==null || certs.length==0) {
  407.         oos.writeInt(0);
  408.     } else {
  409.         // write out the total number of certs
  410.         oos.writeInt(certs.length);
  411.         // write out each cert, including its type
  412.         for (int i=0; i < certs.length; i++) {
  413.         java.security.cert.Certificate cert = certs[i];
  414.         try {
  415.             oos.writeUTF(cert.getType());
  416.             byte[] encoded = cert.getEncoded();
  417.             oos.writeInt(encoded.length);
  418.             oos.write(encoded);
  419.         } catch (CertificateEncodingException cee) {
  420.             throw new IOException(cee.getMessage());
  421.         }
  422.         }
  423.     }
  424.     }
  425.  
  426.     /**
  427.      * Restores this object from a stream (i.e., deserializes it).
  428.      */
  429.     private synchronized void readObject(java.io.ObjectInputStream ois)
  430.     throws IOException, ClassNotFoundException
  431.     {
  432.     CertificateFactory cf;
  433.     Hashtable cfs=null;
  434.  
  435.     ois.defaultReadObject();
  436.  
  437.     // process any new-style certs in the stream (if present)
  438.     int size = ois.readInt();
  439.     if (size > 0) {
  440.         // we know of 3 different cert types: X.509, PGP, SDSI, which
  441.         // could all be present in the stream at the same time
  442.         cfs = new Hashtable(3);
  443.         this.certs = new java.security.cert.Certificate[size];
  444.     }
  445.  
  446.     for (int i=0; i<size; i++) {
  447.         // read the certificate type, and instantiate a certificate
  448.         // factory of that type (reuse existing factory if possible)
  449.         String certType = ois.readUTF();
  450.         if (cfs.containsKey(certType)) {
  451.         // reuse certificate factory
  452.         cf = (CertificateFactory)cfs.get(certType);
  453.         } else {
  454.         // create new certificate factory
  455.         try {
  456.             cf = CertificateFactory.getInstance(certType);
  457.         } catch (CertificateException ce) {
  458.             throw new ClassNotFoundException
  459.             ("Certificate factory for "+certType+" not found");
  460.         }
  461.         // store the certificate factory so we can reuse it later
  462.         cfs.put(certType, cf);
  463.         }
  464.         // parse the certificate
  465.         byte[] encoded=null;
  466.         try {
  467.         encoded = new byte[ois.readInt()];
  468.         } catch (OutOfMemoryError oome) {
  469.         throw new IOException("Certificate too big");
  470.         }
  471.         ois.readFully(encoded);
  472.         ByteArrayInputStream bais = new ByteArrayInputStream(encoded);
  473.         try {
  474.         this.certs[i] = cf.generateCertificate(bais);
  475.         } catch (CertificateException ce) {
  476.         throw new IOException(ce.getMessage());
  477.         }
  478.         bais.close();
  479.     }
  480.     }
  481. }
  482.  
  483.